/*! \file
 * \brief Interface of a few memory-related functions and classes.
 *
 * This library defines a few classes for handeling memory. The Allocator and
 * the AllocatorFast can transparently create and delete memory. The streams can
 * be used to turn a piece of memory into input or output.
 * \author Ivo Wingelaar
 * \date 2011
 * \version 0.1.0
 * \copyright GNU Lesser General Public License v3
 */

#ifndef __MYTH_STREAM_HPP_INCLUDED__
#define __MYTH_STREAM_HPP_INCLUDED__

#include "Myth.hpp"

namespace Myth
{
//! This namespace contains a few stream-related functions and classes.
namespace Stream
{

//! A filter class that takes data, transforms it, and spits it out again.
class Filter : public virtual ReferenceCounter
{
public:
    //! Constructor.
    /*!
     * All classes that derive from this must define a name.
     * \param[in] filter_name The name of the filter.
     */
    Filter(const std::string& filter_name) :
        mFilterName(filter_name)
    {
        //
    }

    //! Virtual destructor.
    virtual ~Filter()
    {
        //
    }

    //! Filter method.
    /*!
     * \return The amount of bytes in the out_buffer.
     * \param[in] in_buffer The data that must be transformed.
     * \param[in] in_size The size of the input.
     * \param[out] out_buffer The place where you want the data to be written.
     */
    virtual uintptr_t filter(const void* in_buffer, uintptr_t in_size, void* out_buffer) = 0;

private:
    //! The name of the filter.
    std::string mFilterName;
};

class Leech : public virtual ReferenceCounter
{
public:

};

//! A reference counted interface to an input of data.
class Input : public virtual ReferenceCounter
{
public:
    //! Constructor.
    /*!
     * All classes that derive from this one must define a name.
     * \param[in] input_name The name of the input.
     */
    Input(const std::string& input_name) :
        mInputName(input_name)
    {
        //
    }

    //! Virtual destructor
    virtual ~Input()
    {
        //
    }

    //! Reads an amount of bytes from the input.
    /*!
     * \return The number of bytes actually read.
     * \param[out] buffer The place to store the data.
     * \param[in] size The number of bytes to request.
     * \throw InputException if something went wrong.
     */
    virtual uintptr_t read(void* buffer, uintptr_t size) = 0;

    //! Changes the position in the data-input.
    /*!
     * \return If the specifief position was reached true is returned, false otherwise.
     * \param[in] position The position you want to seek to.
     * \param[in] relative Should we change the position relative to this, or absolute?
     */
    virtual bool seek(uintptr_t position, bool relative = false) = 0;

    //! Returns the size of the input.
    /*!
     * \return The size of the input.
     */
    virtual uintptr_t get_size(void) const = 0;

    //! Returns the current position of the input.
    /*!
     * \return The current position of the input.
     */
    virtual uintptr_t get_pos(void) const = 0;

    //! Sets the input-name to a new one.
    /*!
     * \param[in] new_name The new name for the input.
     */
    void set_name(const std::string& new_name)
    {
        mInputName = new_name;
    }

    //! Returns the name of the input.
    /*!
     * \return The name of the input.
     */
    std::string get_name(void) const
    {
        return mInputName;
    }

private:
    //! The name of the input.
    std::string mInputName;
};

//! A reference counted interface to an output of data.
class Output : public virtual ReferenceCounter
{
public:
    //! Constructor.
    /*!
     * All classes that derive from this one must define a name.
     * \param[in] output_name The name of the output.
     */
    Output(const std::string& output_name) :
        mOutputName(output_name)
    {
        //
    }

    //! Virtual destructor
    virtual ~Output()
    {
        //
    }

    //! Writes a number of bytes to an output.
    /*!
     * \return The number of bytes written.
     * \param[in] buffer The data to write.
     * \param[in] size The size of the data you want to write.
     * \throw OutputException if something went wrong.
     */
    virtual uintptr_t write(const void* buffer, uintptr_t size) = 0;

    //! Changes the position in the data-output.
    /*!
     * \return If the specifief position was reached true is returned, false otherwise.
     * \param[in] position The position you want to seek to.
     * \param[in] relative Should we change the position relative to this, or absolute?
     */
    virtual bool seek(uintptr_t position, bool relative = false) = 0;

    //! Returns the current position of the input.
    /*!
     * \return The current position of the input.
     */
    virtual uintptr_t get_pos(void) const = 0;

    //! Sets the output-name to a new one.
    /*!
     * \param[in] new_name The new name for the output.
     */
    void set_name(const std::string& new_name)
    {
        mOutputName = new_name;
    }

    //! Returns the name of the output.
    /*!
     * \return The name of the output.
     */
    std::string get_name(void) const
    {
        return mOutputName;
    }

private:
    //! The name of the output.
    std::string mOutputName;
};

} // namespace Stream
} // namespace Myth

#endif // __MYTH_STREAM_HPP_INCLUDED__

